<?php
/**
 *+------------------
 * Lflow
 *+------------------
 * Copyright (c) 2023~2030 gitee.com/liu_guan_qing All rights reserved.本版权不可删除，侵权必究
 *+------------------
 * Author: Mr.April(405784684@qq.com)
 *+------------------
 */
declare (strict_types=1);

namespace lflow\helper;

use lflow\Logger;
use lflow\WorkFlowException;
use RecursiveDirectoryIterator;
use RecursiveIteratorIterator;
use ReflectionClass;
use RegexIterator;

/**
 * 类操作帮助类
 *
 * @author Mr.April
 * @since  1.0
 */
class ClassHelper
{

    /**
     * 根据指定的类名称加载类
     *
     * @param string $className
     *
     * @return \lflow\helper\ProxyHelper
     * @throws \lflow\WorkFlowException
     */
    public static function loadClass(string $className): ProxyHelper
    {
        try {
            return new ProxyHelper($className);
        } catch (WorkFlowException $e) {
            throw new WorkFlowException($e->getMessage());
        }
    }

    /**
     * 实例化指定的类名称（全路径）
     *
     * @param string $clazzStr
     *
     * @return object
     */
    public static function newInstance(string $clazzStr): ?object
    {
        try {
            Logger::debug("loading class:" . $clazzStr);
            return self::loadClass($clazzStr);
        } catch (\Exception $e) {
            Logger:: error("Class not found." . $e->getMessage());
        }
        return null;
    }

    /**
     * 是否包含类
     *
     * @param string $clazzStr
     *
     * @return bool
     */
    public static function inNamespace(string $clazzStr): bool
    {
        try {
            new \ReflectionClass($clazzStr);
            return true;
        } catch (\ReflectionException $e) {
            return false;
        }
    }

    /**
     * 递归导出所有类命名空间
     *
     * @param string $path
     *
     * @return array
     */
    public static function recursiveClass(string $path = __DIR__): array
    {
        try {
            $fqcns    = [];
            $allFiles = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path));
            $phpFiles = new RegexIterator($allFiles, '/\.php$/');
            foreach ($phpFiles as $phpFile) {
                $content   = file_get_contents($phpFile->getRealPath());
                $tokens    = token_get_all($content);
                $namespace = '';
                for ($index = 0; isset($tokens[$index]); $index++) {
                    if (!isset($tokens[$index][0])) {
                        continue;
                    }
                    if (T_NAMESPACE === $tokens[$index][0]) {
                        $index += 2; // Skip namespace keyword and whitespace
                        while (isset($tokens[$index]) && is_array($tokens[$index])) {
                            $namespace .= $tokens[$index++][1];
                        }
                    }
                    if (T_CLASS === $tokens[$index][0]) {
                        $index += 2; // Skip class keyword and whitespace
                        if (!isset($tokens[$index][1])) {
                            continue;
                        }
                        $str = str_replace(array("\r\n", "\r", "\n", " "), "", $tokens[$index][1]);
                        if (empty($str)) {
                            continue;
                        }
                        $fqcns[] = $namespace . '\\' . $str;
                    }
                }
            }
            return $fqcns;
        } catch (\Exception $e) {
            return [];
        }
    }
}